/*---------------------------------------------------------------------------------------------
 *  Copyright (c) kylinIDETeam. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { BrowserWindow, BrowserWindowConstructorOptions, Display, IpcMainEvent, IpcMainInvokeEvent, screen, dialog, shell } from 'electron';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { FileAccess } from 'vs/base/common/network';
import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain';
// import { localize } from 'vs/nls';
// import { IDiagnosticsService } from 'vs/platform/diagnostics/common/diagnostics';
// import { IDiagnosticsMainService } from 'vs/platform/diagnostics/electron-main/diagnosticsMainService';
// import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { IDeployMainService, DeployWindowConfiguration, DeployData } from 'vs/platform/issue/common/deploy';
import { ILogger } from 'vs/platform/log/common/log';
import { ILogService } from 'vs/platform/log/common/log';
import { ILoggerMainService } from 'vs/platform/log/electron-main/loggerService';
import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
import product from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { IIPCObjectUrl, IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol';
// import { IStateService } from 'vs/platform/state/node/state';
import { IWindowState } from 'vs/platform/window/electron-main/window';
// import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { join } from 'vs/base/common/path';
import { Disposable } from 'vs/base/common/lifecycle';
import * as installUtils from 'vs/platform/issue/electron-main/installUtils';
import * as fs from 'fs';
import * as path from 'path';
import axios from "axios";
import { spawn, ChildProcess, execSync } from 'child_process';
import { AbortController } from "@azure/abort-controller";

// const deployWindowState = 'deploy.deployWindowState';
// interface IBrowserWindowOptions {
// 	backgroundColor: string | undefined;
// 	title: string;
// 	zoomLevel: number;
// 	alwaysOnTop: boolean;
// }

// interface installInfo {

// 	// osInfo: string;
// 	IDEVersion: string;
// 	// localConfigData: {};
// 	// urlConfigFile;
// 	localConfigFile: string;
// 	// selectConfigPath;
// 	addNewPage: number;
// 	localosinfo: string;
// 	urlosinfo: string;
// 	urlConfigFile: string;
// }

type IStrictWindowState = Required<Pick<IWindowState, 'x' | 'y' | 'width' | 'height'>>;
export const enum DeployMainPhase {
	// 未开始
	None = 0,
	//开始
	Starting = 1,
	/**
	 * 首页
	 */
	HomePage = 2,

	/**
	 *安装页面
	 */
	InstallPage = 3,

	/**
	 * 取消安装
	 */
	Cancel = 4,
	/**
	  * 安装结束
	  */
	Finish = 5,
	/**
	 * 窗口关闭
	 */
	Close = 6

}

export class DeployMainService implements IDeployMainService {

	declare readonly _serviceBrand: undefined;

	// private static readonly DEFAULT_BACKGROUND_COLOR = '#1E1E1E';

	private DeployWindow: BrowserWindow | null = null;
	private deployWindowrParentWindow: BrowserWindow | null = null;


	private selectObject = {
		dirPath: "",
		updateFlag: false,
		depInfoJsonPath: "", //选中的依赖配置文件路径，
		extAddressPath: "",//选中的插件配置文件路径
	};
	private localConfigObject: { res: number; depConfigInfo: any; g_index_Object: any; osinfo: string; localConfigMatch: number; osrelease: string; supportList: string[] };
	updateConfigObject: { res: number; g_index_Object: any; osinfo: string; ConfigMatch: number; base_url: any; depConfigInfo: any; osrelease: string; supportList: string[] };

	localConfigDir: any;
	localConfigPathname: any;
	installConfig: any;
	updateConfigDir: string;
	baseUrl: string = "";
	extDownloadPath: string = "";
	// public extensionsGalleryConfiguration!: IExtensionsGalleryConfiguration;
	// private preExtensionsGalleryConfig: IExtensionsGalleryConfiguration;
	installQueue: { installCommand: any; msg: any; }[] | null = []; // 定义一个消息队列
	extMap: Record<string, string> = {};
	depList: string[] = [];
	extList: string[] = [];
	lastLogPosition: number = 0;
	//文件监听；
	installFsWatcher: fs.FSWatcher | null = null;
	extlogFsWatcher: fs.FSWatcher | null = null;
	pkglogFsWatcher: fs.FSWatcher | null = null;
	//执行安装脚本的进程号；
	installProcessId: ChildProcess | null = null;
	cancelInstallProcessId: ChildProcess | null = null;
	cancelFlag = false;
	phase: DeployMainPhase;


	offset = 0;
	resultIndex = 0;

	flagPkexec = 0;
	maxBackupFiles = 7;
	lastExtLogPosition = 0;

	logFile0 = "";
	resultFile = "";
	extLogFile0 = "";

	controller = new AbortController();
	DownSelectKey: any = {
		depArry: [],
		goInfoArry: [],
		pip3InfoArry: []
	};

	startInstallDepWatch = 0;
	logger: ILogger;
	loggerExt: ILogger;
	loggerSoft: ILogger;

	constructor(
		private userEnv: IProcessEnvironment,
		@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
		@ILogService private readonly logService: ILogService,
		@ILoggerMainService private readonly loggerMainService: ILoggerMainService,
		@IProtocolMainService private readonly protocolMainService: IProtocolMainService,
		@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,
		@IProductService private readonly productService: IProductService,
	) {
		this.localConfigObject = { depConfigInfo: "", res: 0, g_index_Object: {}, osinfo: "", localConfigMatch: 0, osrelease: "", supportList: [] };
		this.updateConfigObject = { res: 0, g_index_Object: {}, osinfo: "", ConfigMatch: 0, base_url: "", depConfigInfo: "", osrelease: "", supportList: [] };
		this.updateConfigDir = installUtils.installConfigDirPre() + "/" + installUtils.getDateDir();
		this.phase = DeployMainPhase.None;
		this.reset();
		this.logger = this.loggerMainService.createLogger(URI.file(this.installConfig + "/log/instguide.log"));
		this.loggerExt = this.loggerMainService.createLogger(URI.file(this.installConfig + "/log/extdetail.log"));
		this.loggerSoft = this.loggerMainService.createLogger(URI.file(this.installConfig + "/log/softdetail.log"));
		this.removeListeners();
		this.registerListeners();
	}
	reset() {
		this.localConfigObject = { depConfigInfo: "", res: 0, g_index_Object: {}, osinfo: "", localConfigMatch: 0, osrelease: "", supportList: [] };
		this.updateConfigObject = { res: 0, g_index_Object: {}, osinfo: "", ConfigMatch: 0, base_url: "", depConfigInfo: "", osrelease: "", supportList: [] };
		this.localConfigDir = installUtils.localConfigPath();
		this.installConfig = installUtils.installConfigDirPre();//installconfig
		this.updateConfigDir = installUtils.installConfigDirPre() + "/" + installUtils.getDateDir();

		this.logFile0 = this.installConfig + '/log/install.1.log';
		this.resultFile = this.installConfig + '/resultFile';
		this.extLogFile0 = this.installConfig + '/log/extInstall.1.log';
		this.installQueue = [];

		this.baseUrl = "";
		this.extDownloadPath = "";
		this.extMap = {};
		this.depList = [];
		this.extList = [];
		this.lastLogPosition = 0;
		//文件监听；
		this.installFsWatcher = null;
		this.extlogFsWatcher = null;
		this.pkglogFsWatcher = null;
		//执行安装脚本的进程号；
		this.installProcessId = null;
		this.cancelInstallProcessId = null;

		this.cancelFlag = false;
		this.offset = 0;
		this.resultIndex = 0;

		this.flagPkexec = 0;
		this.lastExtLogPosition = 0;

		this.startInstallDepWatch = 0;

		this.controller = new AbortController();
	}
	//#region Register Listeners

	listenerShow = (event: IpcMainEvent, msg: any) => {
		if (msg.type === 'info') {
			if (this.DeployWindow)
				dialog.showMessageBox(this.DeployWindow, {
					type: 'info',
					title: msg.title,
					message: msg.message,
				});
		}

		this.logger.info("显示窗口");
		// this.showWindow();
	};

	listenerHelpLink = (event: IpcMainEvent) => {
		this.logger.info("打开帮助页面");
		this.openHelpLink();
	};
	listenerMiniWindow = (event: IpcMainEvent) => {
		this.logger.info("最小化窗口");
		this.minWindow();
	};
	listenerCloseWindow = (event: IpcMainEvent, msg: any) => {
		if (msg.type === 'skip') {
			this.logService.info("跳过配置");
			this.logger.info("跳过配置");
		}
		if (msg.type === "close") {
			//删除新下载但是没被使用的配置文件
			if (this.updateConfigDir) {
				if (this.selectObject.updateFlag == false)
					if (fs.existsSync(this.updateConfigDir))
						fs.rmdirSync(this.updateConfigDir, { recursive: true });
			}
		}
		this.logService.info("opendeploywindo listenerCloseWindow");
		this.closeWindow();

	};

	listenerFinish = (event: IpcMainEvent, msg: any) => {
		if (msg.type === 'finish') {
			this.phase = DeployMainPhase.Finish;
		}
	};

	listenerInstallProcess = async (event: IpcMainEvent, msg: any) => {
		if (msg.type === 'installExt') {


			const logFile0 = this.installConfig + '/log/extInstall.1.log';

			if (!fs.existsSync(logFile0)) {
				fs.mkdirSync(this.installConfig + "/log", { recursive: true });
			}
			let installCommand = "";
			if (this.cancelFlag) return;
			try {
				const installItem = this.extDownloadPath + msg.downloadDone;
				if (this.environmentMainService.isBuilt) {
					installCommand = "kylin-code" + " " + "--install-extension" + " " + installItem;
				}
				else {
					let comandpath = path.join(FileAccess.asFileUri('').fsPath, '..', "scripts/code-cli.sh")
					installCommand = comandpath + " " + "--install-extension" + " " + installItem;
				}
				this.logger.debug("安装 ext installCommand", installCommand);
				if (this.installQueue?.length === 0) {
					this.logger.info("将命令放入installQueue中", installCommand);
					this.installQueue.push({ installCommand, msg });
					if (!this.cancelFlag) {
						await this.executeNextInstall();
					}

				}
				else {
					if (!this.cancelFlag) {
						this.logger.info("将命令放入installQueue中", installCommand);
						this.installQueue?.push({ installCommand, msg });
					}

				}
			} catch (error) {
				this.logger.error(`安装 ext 执行出错 ${installCommand}: ${error.message}`);
			}
		}
		else if (msg.type === 'installPkg') {
			this.phase = DeployMainPhase.InstallPage;
			this.logger.info("开始安装操作InstallPage");
			this.logger.info("选中的开发场景为:", msg.checkSelectedValues);
			// const extlogFile = this.installConfig + '/log/extInstall.log';
			// this.backupLogFile(extlogFile)
			const extlogFile0 = this.installConfig + '/log/extInstall.1.log';
			fs.writeFileSync(extlogFile0, '');

			if (this.depList.length === 0) {
				const startDownloadExtMsg = {
					type: "extDownloadInit",
				}
				if (this.DeployWindow)
					this.DeployWindow.webContents.send("kylinide.installWizard.msg", startDownloadExtMsg);
				this.lastExtLogPosition = 0;

				fs.watch(this.extLogFile0, (eventType, filename) => {

					if (eventType === 'change') {
						// 获取文件的当前大小
						const stats = fs.statSync(this.extLogFile0);
						const currentSize = stats.size;

						// 计算更新部分的大小
						const updateSize = currentSize - this.lastExtLogPosition;
						if (updateSize <= 0) return;
						// 读取更新部分的内容
						const buffer = Buffer.alloc(updateSize);
						const fileDescriptor = fs.openSync(this.extLogFile0, 'r');
						fs.readSync(fileDescriptor, buffer, 0, updateSize, this.lastExtLogPosition);
						fs.closeSync(fileDescriptor);

						// 将更新部分的内容转换为字符串并输出
						const updatedContent = buffer.toString('utf8');

						// 更新上一次读取的位置
						this.lastExtLogPosition = currentSize;
						const installMsg = {
							type: "extInstallLogPre",
							data: updatedContent
						};

						this.logger.debug("extInstall.1.log 更新内容 :", updatedContent);

						if (this.DeployWindow && !this.cancelFlag)
							this.DeployWindow.webContents.send("kylinide.installWizard.msg", installMsg)

					}

				});
				return;
			}

			this.lastLogPosition = 0;
			this.lastExtLogPosition = 0;
			// const logFile = this.installConfig + '/log/install.log';
			const resultFile = this.installConfig + '/resultFile';
			const installFile = this.installConfig + '/install.sh';
			const logFile0 = this.installConfig + '/log/install.1.log';
			// this.backupLogFile(logFile);

			try {
				fs.writeFileSync(resultFile, '');
				fs.writeFileSync(installFile, '');
				fs.writeFileSync(logFile0, '');
				const installMsg = {
					type: "depStartInstall",
					depName: 'depStartInstall'
				};

				if (this.DeployWindow)
					this.DeployWindow.webContents.send("kylinide.installWizard.msg", installMsg)

				if (this.depList.length === 0) return;

				this.depList.forEach((packageName) => {
					const command = `apt-get install -y ${packageName} >> ${logFile0};\necho $? >> ${resultFile};\n`;
					fs.appendFileSync(installFile, command);
					this.logger.debug("安装 dep Command", command);
				});

				this.executeScriptWithPkexec(installFile);

			} catch (error) {
				this.println(error);
				this.logger.error(`安装 dep 执行出错 : ${error.message}`);
			}
		}
		else if (msg.type === 'installScript') {
			let scriptPath = path.join(this.selectObject.dirPath, msg.script['file_name']);
			if (msg.script['file_name'].endsWith(".js")) {
				try {
					this.loadAndInvokeCancelFunction(scriptPath, "main", this.controller).then((res) => {
						const scriptMsg = {
							type: "scriptExecSucc",
							depName: msg.script['file_name']
						};
						this.logger.info("脚本执行成功:", scriptPath);
						if (this.DeployWindow && !this.cancelFlag)
							this.DeployWindow.webContents.send("kylinide.installWizard.msg", scriptMsg);
					}).catch(err => {
						const scriptMsg = {
							type: "scriptExecFail",
							depName: msg.script['file_name']
						};
						this.logger.error(`${scriptPath}脚本执行失败`, err);
						if (this.DeployWindow && !this.cancelFlag)
							this.DeployWindow.webContents.send("kylinide.installWizard.msg", scriptMsg);
					})
				} catch (err) {
					console.log("err", err);
					const scriptMsg = {
						type: "scriptExecFail",
						depName: msg.script['file_name']
					};
					this.logger.error(`${scriptPath}脚本执行失败:${err}`);
					if (this.DeployWindow && !this.cancelFlag)
						this.DeployWindow.webContents.send("kylinide.installWizard.msg", scriptMsg)
				}

			} else if (msg.script['file_name'].endsWith(".sh")) {
				let command = "sh " + path.join(this.selectObject.dirPath, msg.script['file_name']);
				// await executeCommand(command);
				installUtils.shCancelableTask(command, this.controller, this.logger).then(res => {
					const scriptMsg = {
						type: "scriptExecSucc",
						depName: msg.script['file_name']
					};
					this.logger.info("脚本执行成功:", scriptPath);
					if (this.DeployWindow)
						this.DeployWindow.webContents.send("kylinide.installWizard.msg", scriptMsg)
				}).catch(error => {
					const scriptMsg = {
						type: "scriptExecFail",
						depName: msg.script['file_name']
					};
					this.logger.error(`${scriptPath}脚本执行失败,退出码${error}`);
					if (this.DeployWindow)
						this.DeployWindow.webContents.send("kylinide.installWizard.msg", scriptMsg)
				});

			}
		}
		else if (msg.type == "cancel") {
			this.logger.info("用户点击取消安装按钮");
			//1.结束监听
			//2.结束正在执行的进程，下载，插件安装，软件包安装
			if (this.installProcessId && this.installProcessId.pid && this.installProcessId.exitCode == null && this.flagPkexec == 0) {
				this.logger.info("取消依赖包安装");
				// var killcommand = `pkexec sudo pkill -TERM -P ${installProcessId.pid}`;
				var killcommand = `pkexec sudo pkill -f 'bash ${this.installConfig}/install.sh'`;
				this.cancelInstallProcessId = spawn(killcommand, { shell: true, stdio: 'inherit' });

				this.cancelInstallProcessId.on('exit', (code, signal) => {
					this.logger.info('取消安装结束', code)
					if (code == 127 || code == 126) {
						this.logger.error("取消安装授权失败:", code);
					} else {
						this.cancelFlag = true;
						this.phase = DeployMainPhase.Cancel;
						this.logger.info("取消安装操作Cancel");
						if (this.DeployWindow) {
							this.DeployWindow.webContents.send("kylinide.installWizard.removeFileLister", { type: 'installFile' });
							this.DeployWindow.webContents.send("kylinide.installWizard.removeFileLister", { type: 'extFile' });
							this.DeployWindow.webContents.send("kylinide.installWizard.removeFileLister", { type: 'pkgFile' });
						}
						this.controller.abort();
						this.installQueue?.splice(0);
						this.installQueue = null;
						//结束插件下载及安装
						if (this.DeployWindow) {
							this.DeployWindow.webContents.send("kylinide.installWizard.cancelInstall", { type: "cancelinstall" });
							this.DeployWindow.webContents.send("kylinide.installWizard.msg", { type: "cancelinstall" });
						}
					}
					this.logger.info('kill Exit code:cancelinstallprocessid:', code);
				});
			} else {
				this.controller.abort();
				this.cancelFlag = true;
				this.phase = DeployMainPhase.Cancel;
				this.installQueue?.splice(0);
				this.logger.info("取消安装操作Cancel");
				//结束插件下载及安装
				if (this.DeployWindow) {
					this.DeployWindow.webContents.send("kylinide.installWizard.cancelInstall", { type: 'cancelinstall' });
					this.DeployWindow.webContents.send("kylinide.installWizard.msg", { type: "cancelinstall" });
				}
				if (this.DeployWindow) {
					this.DeployWindow.webContents.send("kylinide.installWizard.removeFileLister", { type: 'installFile' });
					this.DeployWindow.webContents.send("kylinide.installWizard.removeFileLister", { type: 'extFile' });
					this.DeployWindow.webContents.send("kylinide.installWizard.removeFileLister", { type: 'pkgFile' });
				}
			}
		}

	};

	listenerRemoveFileLister = (event: IpcMainEvent, msg: any) => {
		if (msg.type === 'installFile') {
			if (this.installFsWatcher) {
				this.logger.info("关闭安装文件监听");
				this.installFsWatcher.close();
				this.installFsWatcher = null;
			}
		} else if (msg.type === 'extFile') {
			if (this.extlogFsWatcher) {
				this.logger.info("关闭插件安装日志文件监听");
				this.extlogFsWatcher.close();
				this.extlogFsWatcher = null;
			}
		} else if (msg.type === 'pkgFile') {
			if (this.pkglogFsWatcher) {
				this.logger.info("关闭软件包安装日志文件监听");
				this.pkglogFsWatcher.close();
				this.pkglogFsWatcher = null;
			}
		}
	};

	handleInitConfigVersify = async (event: IpcMainInvokeEvent, msg: any) => {
		//start configverify
		// updateConfigDir = msg.dst;
		let selectPageShow = 0;
		let message: string = "";
		this.logger.info("开始校验本地数据");
		this.localConfigObject = await this.localConfigVerify(this.localConfigDir, this.productService.IDEVersion);
		this.logger.info("本地数据校验结束");
		this.logger.info("开始下载校验网络数据");
		this.updateConfigObject = await this.downloadAndVerify(this.updateConfigDir, msg);
		this.logger.info("网络数据校验结束");
		//1.本地error ,net error  -1;
		//2.本地error,net right 1;
		//3.本地 right ,net error 2;
		//4.本地right ,net right  ,==  3
		//5.本地right ,net right , !=  4
		//for test
		if (this.localConfigObject.res != 0 && this.updateConfigObject.res != 0) {
			if (this.DeployWindow) {
				if (this.localConfigObject.osinfo == "undefined" && this.updateConfigObject.osinfo == "undefined") {
					this.logger.error("开发环境快速部署仅支持openKylin操作系统,具体为", this.localConfigObject.supportList);
					await dialog.showMessageBox(this.DeployWindow,
						{
							type: "error",
							title: "配置文件检查",
							buttons: ["OK"],
							detail: `点击【OK】按钮后，将跳过此引导步骤，请根据开发需要自行下载插件、安装软件依赖。具体信息请查看日志${this.installConfig}/log/instguide.log`,
							message: "开发环境快速部署不支持当前系统。"
						});
					if (this.DeployWindow && this.DeployWindow != undefined)
						this.DeployWindow.close();
					// .then(result => {
					// 	if (this.DeployWindow && this.DeployWindow != undefined)
					// 		this.DeployWindow.close();
					// 	resolve(void 0);
					// })
					return void 0;
				} else {
					this.logger.error("本地数据及网络数据校验失败");
					await dialog.showMessageBox(this.DeployWindow,
						{
							type: "error",
							title: "配置文件检查",
							buttons: ["OK"],
							detail: `点击【OK】按钮后，将跳过此引导步骤，请根据开发需要自行下载插件、安装软件依赖。具体信息请查看日志${this.installConfig}/log/instguide.log`,
							message: "本地数据及网络数据校验失败"
						});
					if (this.DeployWindow && this.DeployWindow != undefined)
						this.DeployWindow.close();
					return void 0;
					// .then(result => {
					// 	if (this.DeployWindow && this.DeployWindow != undefined)
					// 		this.DeployWindow.close();
					// 	resolve(void 0);
					// })
				}
			}
			selectPageShow = -1;
		} else {

			if (this.localConfigObject.res != 0 && this.updateConfigObject.res == 0) {

				selectPageShow = 1;
				if (this.localConfigObject.osinfo == "undefined") {
					message = "本地配置文件不支持当前环境，选择更新选项";
					this.logger.error(message);
				} else {
					message = "本地配置文件已损坏，选择更新选项";
					this.logger.error("本地数据校验失败");
				}

			} else if (this.localConfigObject.res == 0 && this.updateConfigObject.res != 0) {
				if (this.updateConfigObject.osinfo == "undefined") {
					message = "联网数据文件不支持当前环境";
					this.logger.error(message);
				} else {
					message = "网络数据文件校验失败";
					this.logger.error(message);
				}
				selectPageShow = 2;
			} else if (this.localConfigObject.res == 0 && this.updateConfigObject.res == 0) {
				if (installUtils.compareVersions(this.updateConfigObject.g_index_Object.ver, this.localConfigObject.g_index_Object.ver) > 0) {
					//显示询问用户是否更新配置文件
					//比较具体的配置文件是否一致，若是一致则还是选择本地配置，若是不同则
					selectPageShow = 4;
					message = "配置文件有更新";
					// if (this.updateConfigObject.g_index_Object["config-file"][updateosinfo][0]['sign-md5'] !== this.localConfigObject.g_index_Object["config-file"][localosinfo][0]['sign-md5'])
					// 	selectPageShow = 4;
					// else {
					// 	this.logger.info("联网数据与本地配置文件数据版本一致");
					// 	selectPageShow = 3;
					// 	message = "联网数据与本地配置文件数据版本一致";
					// }
				} else {
					selectPageShow = 3;
					this.logger.info("联网数据与本地配置文件数据版本一致");
					message = "联网数据与本地配置文件数据版本一致";
				}
			}
			this.println("selectPageShow:" + selectPageShow);
			let Data;
			if (selectPageShow == 0) {
				this.selectObject.depInfoJsonPath = this.localConfigDir + "/" + this.localConfigObject.depConfigInfo['file_name'];
				this.selectObject.extAddressPath = this.localConfigDir + "/" + this.localConfigObject.g_index_Object['ext-file']['file_name'];
				Data = {
					osinfo: this.localConfigObject.osinfo,
					osrelease: this.localConfigObject.osrelease,
					selectPageShow: selectPageShow,
					type: "configVersify"
				}

			} else {
				Data = {
					localConfigObject: this.localConfigObject,
					updateConfigObject: this.updateConfigObject,
					selectPageShow: selectPageShow,
					message: message,
					type: "configVersify"
				}
			}
			if (this.DeployWindow) {
				// this.logger.info('配置文件信息', JSON.stringify(Data));
				return Data;
			} else {
				return void 0;
			}
		}
		return void 0;
	};

	handleInitConfigSelect = async (event: IpcMainInvokeEvent, msg: any) => {
		let osrelease = "";
		if (msg.select === "local") {
			osrelease = this.localConfigObject.osrelease;
			this.selectObject.dirPath = this.localConfigDir;
			this.selectObject.updateFlag = false;
			this.selectObject.depInfoJsonPath = this.localConfigDir + "/" + this.localConfigObject.depConfigInfo['file_name'];
			this.selectObject.extAddressPath = this.localConfigDir + "/" + this.localConfigObject.g_index_Object['ext-file']['file_name'];
		} else if (msg.select === "update") {
			this.selectObject.dirPath = this.updateConfigDir;
			this.selectObject.updateFlag = true;
			osrelease = this.updateConfigObject.osrelease;
			this.selectObject.depInfoJsonPath = this.updateConfigDir + "/" + this.updateConfigObject.depConfigInfo['file_name'];
			this.selectObject.extAddressPath = this.updateConfigDir + "/" + this.updateConfigObject.g_index_Object['ext-file']['file_name']; //error

		}
		const { osFile, data } = this.readOSInfo();
		const osObject = {
			type: "osinfo",
			osrelease: osrelease,
			osFile: osFile,
			osData: data
		}
		this.logger.info(`选择的配置文件名称：${this.selectObject.depInfoJsonPath}`);
		this.logger.info(`识别操作系统信息：${osrelease}`);

		if (this.DeployWindow) {
			// this.DeployWindow.webContents.send('kylinide.installWizard.init', osObject);
			return osObject;
		}
		else {
			return void 0;
		}
	}

	handleInitConfigGetValue = async (event: IpcMainInvokeEvent, msg: any) => {

		const selectJson = installUtils.selectFileJson();
		let selectKey: string[];
		if (selectJson && selectJson.hasOwnProperty('selectKey'))
			selectKey = selectJson['selectKey'];
		else { selectKey = []; }
		this.logger.info(`选择文件配置键：${selectKey.join(' ')}`);
		const Data = {
			type: "configGetValue",
			depInfoData: JSON.parse(fs.readFileSync(this.selectObject.depInfoJsonPath, 'utf-8')),
			depInfoJsonPath: this.selectObject.depInfoJsonPath,
			extAddressPath: this.selectObject.extAddressPath,
			selectKey: selectKey ? selectKey : []
		}
		if (this.DeployWindow) {
			// if (msg.class === "install")
			// 	this.DeployWindow.webContents.send('kylinide.installWizard.init', Data);
			// else if (msg.class === "download") {
			// 	this.DeployWindow.webContents.send('kylinide.installWizard.justDownLoad', Data); // todo
			// }
			return Data;
		}
		else {
			return void 0;
		}
	};

	handleHttpVerify = async (event: IpcMainInvokeEvent, msg: any) => {

		try {
			this.logger.info("检查网络连接...");
			await this.checkHttp();
			this.logger.info("网络连接正常");
			return { type: "httpVerify" };
		} catch (error) {
			this.logger.error("网络连接异常");
			if (this.DeployWindow) {
				dialog.showMessageBox(this.DeployWindow,
					{
						type: "error",
						title: "网络检查",
						message: "网络连接异常，无法使用在线安装"
					});
			}
			return void 0;
		}
		//联网下载、检查、校验配置
	};

	handleDepList = async (event: IpcMainInvokeEvent, msg: any) => {
		this.depList = [];
		this.extList = [];
		// scriptList = [];
		this.depList = msg.depList;
		this.extList = msg.extList;
		this.DownSelectKey.configList = msg.configList;
		// scriptList = message.scriptList;
		this.extMap = {};
		return void 0;
	};

	handleCheckInstall = async (event: IpcMainInvokeEvent, msg: any) => {

		this.println("kylinide.installWizard.checkInstall");
		if (this.startInstallDepWatch === 1) {
			this.logger.info("已开始监听安装文件变化，不再重复监听");
			return;
		}
		this.lastLogPosition = 0;
		this.lastExtLogPosition = 0;
		if (!fs.existsSync(this.logFile0)) {
			fs.mkdirSync(this.installConfig, { recursive: true });
			fs.writeFileSync(this.logFile0, '');
		}
		//监听install pkg输出信息
		this.pkglogFsWatcher =
			fs.watch(this.logFile0, (eventType, filename) => {
				if (eventType === 'change') {
					// 获取文件的当前大小
					const stats = fs.statSync(this.logFile0);
					const currentSize = stats.size;
					if (this.lastLogPosition === 0 && stats.size > 0) {
						const startDownloadExtMsg = {
							type: "extDownloadInit",
						}
						if (this.DeployWindow)
							this.DeployWindow.webContents.send("kylinide.installWizard.msg", startDownloadExtMsg)

						const extlogFile0 = this.installConfig + '/log/extInstall.1.log';
						fs.writeFileSync(extlogFile0, '');
					}

					// 计算更新部分的大小
					const updateSize = currentSize - this.lastLogPosition;
					if (updateSize <= 0) return;

					// 读取更新部分的内容
					const buffer = Buffer.alloc(updateSize);
					const fileDescriptor = fs.openSync(this.logFile0, 'r');
					fs.readSync(fileDescriptor, buffer, 0, updateSize, this.lastLogPosition);
					fs.closeSync(fileDescriptor);

					// 将更新部分的内容转换为字符串并输出
					const updatedContent = buffer.toString('utf8');

					// 更新上一次读取的位置
					this.lastLogPosition = currentSize;
					const installMsg = {
						type: "installLogPre",
						data: updatedContent
					};

					// this.logger.debug(`install pkg输出信息更新：${updatedContent}`);
					if (updatedContent.length > 0)
						fs.appendFileSync(this.installConfig + "/log/softdetail.log", updatedContent);
					if (this.DeployWindow)
						this.DeployWindow.webContents.send("kylinide.installWizard.msg", installMsg);
				}

			});

		//检测ext 安装信息文件变化
		this.extlogFsWatcher =
			fs.watch(this.extLogFile0, (eventType, filename) => {
				if (eventType === 'change') {
					// 获取文件的当前大小
					const stats = fs.statSync(this.extLogFile0);
					const currentSize = stats.size;

					// 计算更新部分的大小
					const updateSize = currentSize - this.lastExtLogPosition;
					if (updateSize <= 0) return;
					// 读取更新部分的内容
					const buffer = Buffer.alloc(updateSize);
					const fileDescriptor = fs.openSync(this.extLogFile0, 'r');
					fs.readSync(fileDescriptor, buffer, 0, updateSize, this.lastExtLogPosition);
					fs.closeSync(fileDescriptor);

					// 将更新部分的内容转换为字符串并输出
					const updatedContent = buffer.toString('utf8');

					// 更新上一次读取的位置
					this.lastExtLogPosition = currentSize;
					const installMsg = {
						type: "extInstallLogPre",
						data: updatedContent
					};

					this.logger.debug(`ext 安装信息更新：${updatedContent}`);

					if (this.DeployWindow)
						this.DeployWindow.webContents.send("kylinide.installWizard.msg", installMsg);
				}
			});

		this.installFsWatcher = fs.watch(this.resultFile, (evenType, filename) => {
			if (evenType === "change") {
				fs.readFile(this.resultFile, "utf8", (err, data) => {
					if (err) {
						this.logger.error(`读取 resultFile 文件时发生错误：${err}`);
						console.error(`读取 resultFile 文件时发生错误：${err}`);
						return;
					}
					// 计算文件变化的部分的偏移量
					const newOffset = data.length;

					// 如果文件没有发生变化，直接返回
					if (newOffset === this.offset) {
						return;
					}

					// 读取文件变化的部分
					const changeData = data.slice(this.offset);

					// 更新文件偏移量
					this.offset = newOffset;

					let result = changeData.trim();
					// 处理文件变化的部分
					this.println(`result ${this.resultIndex + 1} 结果为 ${result} 。`);
					this.logger.debug(`resultFile ${this.resultIndex + 1} 结果为 ${result} 。`);
					//每个dep的安装状态
					let installMsg;
					if (result === '') {
						//此处是因为每次清零的时候会监听到改变
						this.println(`result ${this.resultIndex + 1} 结果为空。`);
						this.logger.debug(`resultFile ${this.resultIndex + 1} 结果为空。`);
						this.resultIndex = 0;
						return;
					} else if (result === '0') {
						installMsg = {
							type: "depInstallSucc",
							depName: this.depList[this.resultIndex],
							result: "0",
							succ: this.resultIndex
						};
						this.logger.info(`依赖包 ${this.depList[this.resultIndex]} 安装成功`);
						if (this.DeployWindow)
							this.DeployWindow.webContents.send("kylinide.installWizard.msg", installMsg);
					} else {
						installMsg = {
							type: "depInstallFail",
							depName: this.depList[this.resultIndex],
							result: "0",
							succ: this.resultIndex //失败
						};
						this.logger.error(`依赖包 ${this.depList[this.resultIndex]} 安装失败`);
						if (this.DeployWindow)
							this.DeployWindow.webContents.send("kylinide.installWizard.msg", installMsg);
					}

					if (this.resultIndex == this.depList.length - 1) {
						if (this.DeployWindow)
							this.DeployWindow.webContents.send("kylinide.installWizard.removeFileLister", { type: "installFile" });
						this.resultIndex = 0;
						return;
					}
					this.resultIndex++;
				});
			}
		});
		this.startInstallDepWatch = 1;
		return void 0;
	};

	handleDownExten = async (event: IpcMainInvokeEvent, message: any) => {

		this.println("kylinide.installWizard.downloadExt");
		this.installQueue?.splice(0);
		let depObject = JSON.parse(fs.readFileSync(message.extAddressPath, 'utf-8'));
		let extLatestDownloadUrlList = [];
		let extDownloadUrlList = [];
		this.extDownloadPath = this.installConfig + '/Download/'

		this.extList.forEach(async (val) => {
			// await semaphore.acquire(); // 获取信号量，控制并发数量

			let gitInfo = depObject[val]['ext_links']['gitee'];
			let tempUrl = gitInfo.prefix + '/' + gitInfo.org + '/' + gitInfo.repo + '/' + 'releases/latest';
			extLatestDownloadUrlList.push(tempUrl);

			// download extension
			try {
				const response = await axios.get(tempUrl, {
					headers: {
						'User-Agent': 'axios',
						'Accept': '*/*',
					},
					timeout: 10000,
					signal: this.controller.signal
				});
				const downloadUrl = response.data.release.release.attach_files[0].download_url;
				const downloadUrlAddr = gitInfo.prefix + downloadUrl;
				extDownloadUrlList.push(downloadUrlAddr);
				const start = downloadUrlAddr.lastIndexOf('/') + 1;
				const filename = downloadUrlAddr.slice(start);
				this.extMap[val] = filename;

				const startDownloadMsg = {
					type: 'extStartDownload',
					extName: val,
					extMap: this.extMap,
					// extTotal: extMap.length,
					extTotal: this.extList.length,
				};
				if (this.DeployWindow)
					this.DeployWindow.webContents.send('kylinide.installWizard.msg', startDownloadMsg);
				if (!this.cancelFlag) {
					//检查缓存目录是否已经存在插件
					this.logger.info(`开始下载扩展 ${val} 到 ${this.extDownloadPath + filename} 从 ${downloadUrlAddr}`);
					this.download_VSIX(downloadUrlAddr, this.extDownloadPath + filename, this.controller).then((result) => {
						const msg = {
							type: 'downloadExtDone',
							fileName: filename,
							extName: val,
							extMap: this.extMap,
							extTotal: Object.keys(this.extMap).length,
						};
						if (result === 0) {
							if (this.DeployWindow) this.DeployWindow.webContents.send('kylinide.installWizard.msg', msg);
						}
					}).catch((error) => {
						this.logger.error(`下载扩展 ${val} 异常: ${error}`);
						const msg = {
							type: 'downloadExtFail',
							fileName: filename ? filename : val,
							extName: val,
							extMap: this.extMap,
							// extTotal: Object.keys(extMap).length,
							extTotal: this.extList.length,
						};
						if (this.DeployWindow) this.DeployWindow.webContents.send('kylinide.installWizard.msg', msg);

					});


				}
			} catch (error) {
				this.logger.error(`下载 ${val} 异常: ${error}`);
				const msg = {
					type: 'downloadExtFail',
					fileName: val,
					extName: val,
					extMap: this.extMap,
					// extTotal: Object.keys(extMap).length,
					extTotal: this.extList.length,
				};
				if (this.DeployWindow) this.DeployWindow.webContents.send('kylinide.installWizard.msg', msg);

			} finally {
				// semaphore.release(); // 释放信号量
			}
		});
		return void 0;
	};

	listenerWriteSelectJson = async (event: IpcMainEvent, msg: any) => {
		if (msg.type === "writeJson") {
			if (this.selectObject.updateFlag) {
				this.logger.info(`更新配置文件地址为:`, this.updateConfigDir);
				installUtils.modifyJsonProperty(path.join(this.installConfig, "selectFile.json"), "selectDir", this.updateConfigDir);
			}
			// else {
			// 	installUtils.modifyJsonProperty(this.installConfig + "/" + "selectFile.json", "selectDir", this.localConfigDir);
			// }
		} else if (msg.type === 'writeKey') {
			this.logger.info("保存选择的开发场景");
			installUtils.modifyJsonProperty(this.installConfig + "/" + "selectFile.json", "selectKey", msg.keys);
		}
	};
	private removeListeners(): void {
		this.logger.info("移除监听器");
		//接收从渲染进程发送的消息
		validatedIpcMain.removeListener('kylinide.installWizard.show', this.listenerShow);
		validatedIpcMain.removeListener('kylinide.installWizard.helpLink', this.listenerHelpLink);
		validatedIpcMain.removeListener('kylinide.installWizard.minw', this.listenerMiniWindow);
		validatedIpcMain.removeListener('kylinide.installWizard.closeWizard', this.listenerCloseWindow);
		validatedIpcMain.removeListener('kylinide.installWizard.msg.process', this.listenerInstallProcess);
		validatedIpcMain.removeListener('kylinide.installWizard.removeFileLister', this.listenerRemoveFileLister);
		validatedIpcMain.removeListener('kylinide.installWizard.init', this.listenerWriteSelectJson);
		validatedIpcMain.removeListener('kylinide.installWizard.reloadwindow', this.listenerReloadWindow);
		validatedIpcMain.removeListener('kylinide.installWizard.downloadExt', this.handleDownExten);
		validatedIpcMain.removeListener('kylinide.installWizard.finish', this.listenerFinish);
	}
	private registerListeners(): void {
		this.logger.info("注册监听器");
		//接收从渲染进程发送的消息
		validatedIpcMain.on('kylinide.installWizard.show', this.listenerShow);
		validatedIpcMain.on('kylinide.installWizard.helpLink', this.listenerHelpLink);
		validatedIpcMain.on('kylinide.installWizard.minw', this.listenerMiniWindow);
		validatedIpcMain.on('kylinide.installWizard.closeWizard', this.listenerCloseWindow);
		validatedIpcMain.on('kylinide.installWizard.msg.process', this.listenerInstallProcess);
		validatedIpcMain.on('kylinide.installWizard.removeFileLister', this.listenerRemoveFileLister);
		validatedIpcMain.on('kylinide.installWizard.init', this.listenerWriteSelectJson);
		validatedIpcMain.on('kylinide.installWizard.reloadwindow', this.listenerReloadWindow);
		validatedIpcMain.on('kylinide.installWizard.finish', this.listenerFinish);

		//handle从渲染进程发送的消息
		validatedIpcMain.handle('kylinide.installWizard.init.configVersify', this.handleInitConfigVersify);
		validatedIpcMain.handle('kylinide.installWizard.init.configSelect', this.handleInitConfigSelect);
		validatedIpcMain.handle('kylinide.installWizard.init.configGetValue', this.handleInitConfigGetValue);
		validatedIpcMain.handle('kylinide.installWizard.init.httpVerify', this.handleHttpVerify);
		validatedIpcMain.handle('kylinide.installWizard.msg.deplist', this.handleDepList);
		validatedIpcMain.handle('kylinide.installWizard.checkInstall', this.handleCheckInstall);
		validatedIpcMain.on('kylinide.installWizard.downloadExt', this.handleDownExten);

	}
	//#endregion

	executeScriptWithPkexec(scriptPath: string) {
		this.flagPkexec = 0;
		this.println("executeScriptWithPkexec");
		try {
			const pkexecCommand = `pkexec sudo bash ${scriptPath}`;
			this.logger.info(`执行命令 ${pkexecCommand}`);
			this.loggerSoft.info(`执行命令 ${pkexecCommand}`);
			this.installProcessId = spawn(pkexecCommand, { shell: true, stdio: 'inherit' });

			this.installProcessId.on('exit', (code, signal) => {
				this.flagPkexec++;
				this.logger.info(`执行命令 ${pkexecCommand} 结束，退出码：${code}`);
				this.loggerSoft.info(`执行命令 ${pkexecCommand} 结束，退出码：${code}`);
				if (code == 127) {
					//授权失败，结束安装。
					if (this.DeployWindow) {
						this.DeployWindow.webContents.send("kylinide.installWizard.Auth", { type: "pkgNotAuth" });
						this.DeployWindow.webContents.send("kylinide.installWizard.msg", { type: "cancelinstall" });
					}
				}
			});

		} catch (error) {
			this.logger.error(`执行脚本时出错: ${error.message}`);
			this.loggerSoft.error(`执行脚本时出错: ${error.message}`);
			// return false;
		}
	}

	// 获取备份文件名
	getBackupFileName(filePath: string, index: number) {
		const path = require('path');
		const extname = path.extname(filePath);
		const basename = path.basename(filePath, extname);
		return `${basename}.${index}${extname}`;
	}

	// 备份日志文件
	backupLogFile(filePath: string) {
		const path = require('path');
		for (let i = this.maxBackupFiles - 1; i >= 0; i--) {
			const currentFileName = i === 0 ? filePath : this.getBackupFileName(filePath, i);
			const nextFileName = this.getBackupFileName(filePath, i + 1);
			const currentFilePath = path.join(path.dirname(filePath), currentFileName);
			const nextFilePath = path.join(path.dirname(filePath), nextFileName);

			if (fs.existsSync(currentFilePath)) {
				if (i === this.maxBackupFiles - 1) {
					if (fs.existsSync(nextFileName))
						fs.unlinkSync(nextFilePath);
				}
				fs.copyFileSync(currentFilePath, nextFilePath);
			}
		}
	}
	async executeNextInstall() {
		if (this.installQueue?.length === 0) {
			return; // 队列为空，结束执行
		}
		if (this.cancelFlag) {
			this.installQueue?.splice(0);
			return;
		}
		if (!this.installQueue)
			return;

		const { installCommand, msg } = this.installQueue[0];
		try {
			const extlogFile = this.installConfig + '/log/extInstall.1.log';
			this.logger.info(`开始执行${installCommand}`);
			let ret: { stdout: string, stderr: string } = await this.spawnCommand(installCommand) as { stdout: string; stderr: string; };
			if (ret.stdout) {
				fs.appendFileSync(extlogFile, ret.stdout);
				this.loggerExt.info(ret.stdout);
			}

			// if (ret.stderr)
			// 	fs.appendFileSync(extlogFile, ret.stderr);
			this.logger.info(`执行命令成功 ${installCommand}`);
			this.loggerExt.info(`执行命令成功 ${installCommand}`);

			const installMsg = {
				type: "extInstalled",
				extFileName: msg.downloadDone,
				// extTotal: Object.keys(extMap).length,
				extTotal: this.extList.length
			};
			if (this.DeployWindow && !this.cancelFlag) {
				this.DeployWindow.webContents.send("kylinide.installWizard.msg", installMsg);
			} else {
				this.installQueue.splice(0);
			}
		} catch (error) {
			this.logger.error(`执行命令失败 ${installCommand}：${error.message}`);
			const extlogFile = this.installConfig + '/log/extInstall.1.log';
			fs.appendFileSync(extlogFile, installCommand);
			fs.appendFileSync(extlogFile, '\n');
			fs.appendFileSync(extlogFile, error.message);
			fs.appendFileSync(extlogFile, '\n');
			this.loggerExt.info(`执行命令失败 ${installCommand}`);
			this.loggerExt.info(error.message);
			const installMsg = {
				type: "extInstalledFail",
				extFileName: msg.downloadDone,
				extTotal: this.extList.length,
				extName: msg.extName
			};
			if (this.DeployWindow && !this.cancelFlag) {
				this.DeployWindow.webContents.send("kylinide.installWizard.msg", installMsg);
			} else {
				this.installQueue.splice(0);
			}
		}

		this.installQueue.shift(); // 执行完成后，将当前消息从队列中移除
		if (!this.cancelFlag && this.installQueue.length > 0)
			await this.executeNextInstall(); // 继续执行下一个消息
		else { this.installQueue.splice(0) }
	}

	spawnCommand(command: string) {
		return new Promise((resolve, reject) => {
			const child = spawn('sh', ['-c', command], { detached: true });

			let stdout = '';
			let stderr = '';

			child.stdout.on('data', (data) => {
				stdout += data.toString();
			});

			child.stderr.on('data', (data) => {
				stderr += data.toString();
			});

			child.on('close', (code) => {
				clearTimeout(timer);
				this.controller.signal.removeEventListener('abort', cancelTask);
				if (code === 0) {
					resolve({ stdout, stderr });
				} else {
					reject(new Error(`Command failed with exit code ${code} `));
				}
			});
			const timer = setTimeout(() => {
				reject(new Error('命令执行超时'));
				if (child && child.pid) {
					execSync(`kill -9 -${child.pid}`);
				}
			}, 1200000);
			const cancelTask = () => {
				if (child.pid) {
					reject(new Error('取消命令'))
					execSync(`kill -9 -${child.pid}`);
				}

			}
			this.controller.signal.addEventListener('abort', cancelTask);
		});
	}

	async executeCommand(command: string) {
		return new Promise<void>((resolve, reject) => {
			const { exec } = require('child_process');
			exec(command, (error: any, stdout: any, stderr: any) => {
				if (error) {
					this.logger.error(`执行命令失败 ${command}：${error.message}`);
					reject(error);
				} else {
					this.logger.info(`执行命令成功 ${command}`);
					resolve();
				}
			});
		});
	}


	minWindow() {
		if (this.DeployWindow) {
			this.DeployWindow.minimize();
		}
	}

	closeWindow() {
		this.logService.info("deploywindow closeWindow");
		if (this.DeployWindow) {
			if (this.installProcessId) {
				this.installProcessId.kill();
			}
			if (this.cancelInstallProcessId) {
				this.cancelInstallProcessId.kill();
			}

			this.DeployWindow.close();
		}
	}

	println(message?: any, ...optionalParams: any[]) {
		console.log(message, ...optionalParams);
	}

	//#region Used by renderer


	async openDeployWindow(flag: boolean = true): Promise<void> {
		return new Promise(async (resolve, reject) => {
			if (!this.DeployWindow) {
				if (!flag)
					this.deployWindowrParentWindow = BrowserWindow.getFocusedWindow();

				this.reset();
				this.logger.info("开始创建界面Starting");
				this.phase = DeployMainPhase.Starting;
				const data = {} as DeployData;
				const DeployDisposables = new DisposableStore();
				const deployWindowConfigUrl = DeployDisposables.add(this.protocolMainService.createIPCObjectUrl<DeployWindowConfiguration>());
				this.logger.info("打开窗口 deployWindowConfigUrl地址", deployWindowConfigUrl.resource.toString());
				const position = this.getDeployWindowPosition(624, 500);
				this.DeployWindow = this.createDeployBrowserWindow(position, deployWindowConfigUrl, 'deploy');
				// // Store into config object URL
				deployWindowConfigUrl.update({
					appRoot: this.environmentMainService.appRoot,
					windowId: this.DeployWindow.id,
					userEnv: this.userEnv,
					data,
					product
				});
				this.DeployWindow.loadURL(
					FileAccess.asBrowserUri(`vs/code/electron-sandbox/deploy/deployWindow${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true)
				);
				// this.DeployWindow.webContents.openDevTools();

				let initData = {
					isFirstLoad: flag,
					logPath: path.join(this.installConfig, 'log')
				}
				this.DeployWindow.webContents.on('did-finish-load', () => {
					if (this.DeployWindow) {
						this.logger.info("窗口加载完成，显示首页HomePage", "send kylinide.installWizard.initdata");
						this.DeployWindow.webContents.send('kylinide.installWizard.initdata', initData);
						this.DeployWindow.show();
						this.phase = DeployMainPhase.HomePage;
					}
				});

				this.DeployWindow.on('close', e => {
					this.logger.info("接收到关闭窗口的信号");
					this.logger.info("检查是否能够关闭窗口");
					if (this.phase === DeployMainPhase.InstallPage) {
						this.logger.info("安装未结束，请先点击取消，然后关闭窗口");
						e.preventDefault();
						if (this.DeployWindow) {
							this.DeployWindow.show();
							dialog.showMessageBox(this.DeployWindow, {
								type: 'info',
								title: "提示",
								message: "开发环境快速部署功能正在进行安装操作...",
								detail: '请先点击开发环境快速部署右上方取消按钮，然后再关闭窗口'
							})
						}
						return;
					}
					this.logger.info("关闭窗口");
					this.DeployWindow = null;
					try {
						DeployDisposables.dispose();
					} catch {
						this.logger.info("deployDisposables.dispose");
					}
					this.phase = DeployMainPhase.Close;
					resolve(void 0);
				});
				this.deployWindowrParentWindow?.on('close', () => {
					this.deployWindowrParentWindow = null;
				})
				// const listenerSkipWizard = async (event: IpcMainEvent) => {
				// 	this.logger.info("跳过配置");
				// 	if (this.DeployWindow && this.DeployWindow != undefined) {
				// 		this.DeployWindow.close();
				// 	}
				// }
				// validatedIpcMain.on('kylinide.installWizard.skipWizard', listenerSkipWizard
				// );
			}
			if (this.DeployWindow) {
				this.focusWindow(this.DeployWindow);
			}
		});
	}


	listenerReloadWindow = async (event: IpcMainEvent, msg: any) => {
		if (this.deployWindowrParentWindow) {
			this.deployWindowrParentWindow.show();
			dialog.showMessageBox(this.deployWindowrParentWindow, {
				type: 'question',
				title: "确认",
				buttons: ["是", '否'],
				defaultId: 0,
				message: "是否重新加载窗口?",
				detail: '开发环境快速部署安装插件后需要重载窗口使插件生效',
			}).then(res => {
				if (res.response === 0) {
					if (this.deployWindowrParentWindow)
						this.nativeHostMainService.reload(this.deployWindowrParentWindow.id);
				}
			})
		}
	}
	private createDeployBrowserWindow<T>(position: IWindowState, ipcObjectUrl: IIPCObjectUrl<T>, windowKind: string): BrowserWindow {
		const window = new BrowserWindow({
			fullscreen: false,
			resizable: false,
			width: position.width,
			height: position.height,
			minWidth: 300,
			minHeight: 200,
			x: position.x,
			y: position.y,
			backgroundColor: '#00000000',
			transparent: true,
			maximizable: false,
			show: false,
			// backgroundColor: DeployMainService.DEFAULT_BACKGROUND_COLOR,
			webPreferences: {
				preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-sandbox/deploypreload.js').fsPath,
				additionalArguments: [`--vscode-window-config=${ipcObjectUrl.resource.toString()}`],
				v8CacheOptions: this.environmentMainService.useCodeCache ? 'bypassHeatCheck' : 'none',
				enableWebSQL: false,
				spellcheck: false,
				sandbox: true
			},
			alwaysOnTop: false,
			titleBarStyle: 'hidden',
			icon: join(this.environmentMainService.appRoot, 'resources/linux/code.png'),
			frame: false
		} as BrowserWindowConstructorOptions & { experimentalDarkMode: true })
		return window;
	}
	private getDeployWindowPosition(defaultWidth: number, defaultHeight: number): IStrictWindowState {

		// We want the new window to open on the same display that the parent is in
		let displayToUse: Display | undefined;
		const displays = screen.getAllDisplays();

		// Single Display
		if (displays.length === 1) {
			displayToUse = displays[0];
		}

		// Multi Display
		else {

			// on mac there is 1 menu per window so we need to use the monitor where the cursor currently is
			if (isMacintosh) {
				const cursorPoint = screen.getCursorScreenPoint();
				displayToUse = screen.getDisplayNearestPoint(cursorPoint);
			}
			// fallback to primary display or first display
			if (!displayToUse) {
				displayToUse = screen.getPrimaryDisplay() || displays[0];
			}
		}

		const displayBounds = displayToUse.bounds;

		const state: IStrictWindowState = {
			width: defaultWidth,
			height: defaultHeight,
			x: displayBounds.x + (displayBounds.width / 2) - (defaultWidth / 2),
			y: displayBounds.y + (displayBounds.height / 2) - (defaultHeight / 2)
		};

		if (displayBounds.width > 0 && displayBounds.height > 0 /* Linux X11 sessions sometimes report wrong display bounds */) {
			if (state.x < displayBounds.x) {
				state.x = displayBounds.x; // prevent window from falling out of the screen to the left
			}

			if (state.y < displayBounds.y) {
				state.y = displayBounds.y; // prevent window from falling out of the screen to the top
			}

			if (state.x > (displayBounds.x + displayBounds.width)) {
				state.x = displayBounds.x; // prevent window from falling out of the screen to the right
			}

			if (state.y > (displayBounds.y + displayBounds.height)) {
				state.y = displayBounds.y; // prevent window from falling out of the screen to the bottom
			}

			if (state.width! > displayBounds.width) {
				state.width = displayBounds.width; // prevent window from exceeding display bounds width
			}

			if (state.height! > displayBounds.height) {
				state.height = displayBounds.height; // prevent window from exceeding display bounds height
			}
		}

		return state;
	}
	private focusWindow(window: BrowserWindow): void {
		if (window.isMinimized()) {
			window.restore();
		}

		window.focus();
	}

	private openHelpLink(): void {
		if (this.productService.helpDocUrl) {
			shell.openExternal(this.productService.helpDocUrl);
			return;
		}
	}

	checkHttp() {
		return new Promise((resolve, reject) => {
			axios.get("https://www.gitee.com/favicon.ico", { timeout: 10000 }).then(response => {
				resolve(200);
			}).catch(error => {
				if (error.code === 'ECONNABORTED') {
					reject(-1);
					this.logger.error('网络请求验证超时');
				} else {
					reject(-1);
					this.logger.error('网络连接发生错误:', error);
				}
			})
		})
	}

	private replaceBaseUrl(url: string, baseurl: string) {
		if (url.startsWith("base-url:")) {
			url = url.replace("base-url:", baseurl);
		}
		return url;
	}

	private getPublicKeyPem(publicKeyPath: string) {
		const data = fs.readFileSync(publicKeyPath, 'utf-8');
		return data;
	}

	private versify(dataPath: string, signature: string) {
		const crypto = require('crypto');
		const publicKeyPath = path.join(FileAccess.asFileUri('').fsPath, '..', "installwizard/key/public.pem");
		this.logger.info("publicKeyPath", publicKeyPath);
		//获取数据
		const dataToSign = fs.readFileSync(dataPath, 'utf-8');

		var md5 = crypto.createHash('md5');
		var md5data = md5.update(dataToSign).digest('hex');
		//获取公钥
		var publicKeyPem = this.getPublicKeyPem(publicKeyPath);
		var publicKey = crypto.createPublicKey({ key: publicKeyPem, format: 'pem', type: 'pkcs1' });
		// 验证签名
		const verify = crypto.createVerify('RSA-SHA256');
		verify.update(md5data);
		const isVerified = verify.verify(publicKey, signature, 'hex');
		if (isVerified) {
			this.logger.info("签名验证成功:" + dataPath);
		} else {
			this.logger.info("签名验证失败:" + dataPath);
		}
		return isVerified
	}

	//下载文件
	private async download_File(url_git: string, dst: string, controller?: AbortController) {
		try {
			const response = await axios.get(url_git, { responseType: 'stream', timeout: 10000, signal: controller?.signal });
			const directoryPath = path.dirname(dst);
			// 判断目录是否存在
			if (!fs.existsSync(directoryPath)) {
				// 创建目录
				fs.mkdirSync(directoryPath, { recursive: true });
			}

			const writer = fs.createWriteStream(dst);
			response.data.pipe(writer);

			return new Promise((resolve, reject) => {
				writer.on('finish', () => {
					this.logger.info("文件下载成功：" + dst);
					resolve(0);
				});

				response.data.on('error', () => {
					this.logger.error("文件下载失败：" + dst, "response data on error");
					if (fs.existsSync(dst)) {
						fs.unlinkSync(dst);
					}
					reject(-1);
				});

				writer.on('error', (err) => {
					console.error('写入文件时发生错误:', err);
					if (fs.existsSync(dst)) {
						fs.unlinkSync(dst);
					}
					reject(-1);
				});
			});
		} catch (error) {
			this.logger.error("文件下载失败：" + dst);
			if (axios.isCancel(error)) {
				this.logger.error('请求已取消');
			}
			else if (error.code === 'ECONNABORTED') {
				this.logger.error("请求超时");
			} else {
				this.logger.error('请求发生错误', error.message);
			}
			return Promise.reject(-1);
		}
	}

	private async download_VSIX(url_git: string, dst: string, controller?: AbortController) {
		return new Promise(async (resolve, reject) => {
			try {
				const directoryPath = path.dirname(dst);
				// 判断目录是否存在
				if (!fs.existsSync(directoryPath)) {
					// 创建目录
					fs.mkdirSync(directoryPath, { recursive: true });
				}
				const response = await axios.get(url_git, { responseType: 'stream', timeout: 10000, signal: this.controller?.signal });
				const writer = fs.createWriteStream(dst);
				response.data.pipe(writer);
				writer.on('open', () => {
					this.logger.info("文件开始写入：" + dst);
				});
				writer.on('finish', () => {
					this.logger.info("文件下载成功：" + dst);
					resolve(0);
				});
				response.data.on('error', () => {
					this.logger.error("文件下载失败：" + dst, "response data on error");
					if (fs.existsSync(dst)) {
						fs.unlinkSync(dst);
					}
					reject(-1);
				});
				writer.on('error', (err) => {
					this.logger.error('文件下载失败，写入文件时发生错误:', dst, err);
					if (fs.existsSync(dst)) {
						fs.unlinkSync(dst);
					}
					reject(-1);
				});

			} catch (error) {
				this.logger.error("文件下载失败：" + dst);
				if (axios.isCancel(error)) {
					this.logger.error('文件下载请求已取消', dst);
				}
				else if (error.code === 'ECONNABORTED') {
					this.logger.error("文件下载请求超时", dst);
				} else {
					this.logger.error('文件下载请求发生错误', dst, error);
				}
				reject(-1);
			}
		})
	}


	private async localConfigVerify(configDir: string, IDEVersion: string) {
		try {
			var dst = path.join(configDir, "./g_index.json");
			var g_index_localDataObject = JSON.parse(fs.readFileSync(dst, 'utf-8'));
			let flag = 0;
			//获取到判断操作系统的脚本文件
			var match_script_file_name = g_index_localDataObject["match-script"]["file_name"];
			var match_script_file_sign = g_index_localDataObject["match-script"]["sign-md5"];
			var match_script_filePath = path.join(configDir, `${match_script_file_name}`);
			//获取到存放插件仓库的配置文件
			var match_ext_file_name = g_index_localDataObject["ext-file"]["file_name"];
			var match_ext_file_sign = g_index_localDataObject["ext-file"]["sign-md5"];
			var match_ext_filePath = path.join(configDir, `${match_ext_file_name}`);

			//校验本地数据是否有问题
			if (!this.versify(`${match_script_filePath}`, match_script_file_sign)) {
				flag++;
			}
			if (!this.versify(`${match_ext_filePath}`, match_ext_file_sign)) {
				flag++;
			}
			//执行脚本，获取操作系统标识信息
			const functionName = 'getoscontent';
			let [osinfo, osrelease, supportList] = await this.loadAndInvokeFunction(match_script_filePath, functionName);
			//执行脚本，获取操作系统信息
			// const  = await this.loadAndInvokeFunction(match_script_filePath, "showosinfo");
			//执行脚本，获取操作系统信息

			this.logger.info("通过脚本" + match_script_filePath + "获取操作系统信息" + osrelease);
			let localConfigMatch = 0;
			// 检测文件是否有osinfo想匹配的
			if (g_index_localDataObject["config-file"].hasOwnProperty(`${osinfo}`)) {
				if (installUtils.compareVersions(g_index_localDataObject['config-file'][osinfo][0]["kylin-ide-lowest-ver"], IDEVersion) == 1) {
					this.logger.info("本地配置文件版本与当前ide版本不兼容");
					flag++;
				} else {
					if (!this.versify(path.join(installUtils.localConfigPath(), `${g_index_localDataObject['config-file'][osinfo][0]['file_name']}`), `${g_index_localDataObject['config-file'][osinfo][0]['sign-md5']}`)) {
						flag++;
					} else {
						localConfigMatch = 1;
					}
				}

				//校验相关的脚本文件
				var depFileName = g_index_localDataObject['config-file'][osinfo][0]['file_name'];
				var depObject = JSON.parse(fs.readFileSync(path.join(configDir, depFileName), 'utf-8'));
				Object.keys(depObject['second_class']).forEach((key) => {
					var object = depObject['second_class'][key]['script-list'];
					for (let i = 0; i < object.length; i++) {
						var file_name: string;
						var sign_md5: string;
						file_name = object[i]["file_name"];
						sign_md5 = object[i]["sign-md5"];
						if (!this.versify(path.join(configDir, file_name), sign_md5)) {
							this.logger.error(path.join(configDir, file_name) + "文件校验失败");
							flag++;
						} else {
							this.println(path.join(configDir, file_name) + "文件校验正确");
						}
					}
				});

			} else {
				flag++;
			}

			let res = flag > 0 ? -1 : 0

			let configData = {
				res: res,
				g_index_Object: g_index_localDataObject,
				osinfo: osinfo,
				osrelease: osrelease,
				supportList: supportList,
				localConfigMatch: localConfigMatch,
				depConfigInfo: osinfo !== "undefined" ? g_index_localDataObject['config-file'][osinfo][0] : {}
			}
			return configData;
		} catch (error: any) {
			this.logger.error("本地数据校验失败" + error);
			let configData = {
				res: -1,
				g_index_Object: "",
				osinfo: "",
				localConfigMatch: -1,
				depConfigInfo: {},
				osrelease: "",
				supportList: []
			}
			return configData;
		}
	}

	private async downloadAndVerify(updateConfigDir: string, arg: any) {
		// updateConfigDir = arg.dst;
		let g_index_url = this.productService.gIndexUrl;
		try {
			const dst = updateConfigDir + '/g_index.json';
			if (!fs.existsSync(updateConfigDir)) {
				fs.mkdirSync(updateConfigDir, { recursive: true })
			}
			var g_index_Object;
			var flag = 0;
			let status = await this.download_File(g_index_url, dst);
			if (status === 0) {
				//读取全局文件
				g_index_Object = JSON.parse(fs.readFileSync(dst, 'utf-8'));
				//下载脚本文件
				let extLinkAddrPath = updateConfigDir + '/' + g_index_Object['ext-file']['file_name'];
				const res1 = await this.download_File(this.replaceBaseUrl(g_index_Object['ext-file']['file_url'], g_index_Object['base-url']), extLinkAddrPath);
				//下载插件配置文件
				const res2 = await this.download_File(this.replaceBaseUrl(g_index_Object['match-script']['file_url'], g_index_Object['base-url']), `${updateConfigDir}/${g_index_Object['match-script']['file_name']}`);
				if (res1 != 0 || res2 != 0) {
					flag++;
				}
			} else {
				flag++;
			}
			this.baseUrl = g_index_Object['base-url'];

			//获取到判断操作系统的脚本文件
			var match_script_file_name = g_index_Object["match-script"]["file_name"];
			var match_script_file_sign = g_index_Object["match-script"]["sign-md5"];
			var match_script_filePath = path.join(updateConfigDir, `./${match_script_file_name}`);
			//获取到存放插件仓库的配置文件
			var match_ext_file_name = g_index_Object["ext-file"]["file_name"];
			var match_ext_file_sign = g_index_Object["ext-file"]["sign-md5"];
			var match_ext_filePath = path.join(updateConfigDir, `./${match_ext_file_name}`);

			//校验本地数据是否有问题
			if (!this.versify(`${match_script_filePath}`, match_script_file_sign)) {
				flag++;
			}
			if (!this.versify(`${match_ext_filePath}`, match_ext_file_sign)) {
				this.println("app ext verifysign error");
				flag++;
			}
			//执行脚本，获取操作系统信息
			const functionName = 'getoscontent';
			let [osinfo, osrelease, supportList] = await this.loadAndInvokeFunction(match_script_filePath, functionName);
			this.logger.info("通过脚本" + match_script_filePath + "获取操作系统信息" + osrelease);

			let ConfigMatch = 0;
			// 检测文件是否有osinfo想匹配的
			if (osinfo !== 'undefined') {
				if (g_index_Object["config-file"].hasOwnProperty(`${osinfo}`)) {
					if (installUtils.compareVersions(g_index_Object['config-file'][osinfo][0]["kylin-ide-lowest-ver"], this.productService.IDEVersion) == 1) {
						this.logger.info("网上的配置文件版本与当前code版本不兼容");
						flag++;
					} else {
						//下载和当前操作系统关联的插件配置文件
						var depUrl = g_index_Object['config-file'][osinfo][0]['file_url'];
						var osConfigDst = updateConfigDir + '/' + g_index_Object['config-file'][osinfo][0]['file_name'];
						let status1 = await this.download_File(this.replaceBaseUrl(depUrl, g_index_Object['base-url']), osConfigDst);
						if (status1 === 0) {
							if (!this.versify(osConfigDst, g_index_Object['config-file'][osinfo][0]['sign-md5'])) {
								flag++;
							}
						} else {
							flag++;
						}
					}
					//校验相关的脚本文件
					var depFileName = g_index_Object['config-file'][osinfo][0]['file_name'];
					var depObject = JSON.parse(fs.readFileSync(path.join(updateConfigDir, depFileName), 'utf-8'));
					Object.keys(depObject['second_class']).forEach(async (key) => {
						var object = depObject['second_class'][key]['script-list'];
						for (let i = 0; i < object.length; i++) {
							var file_name: string;
							var sign_md5: string;
							var file_url: string;
							file_name = object[i]["file_name"];
							sign_md5 = object[i]["sign-md5"];
							file_url = object[i]['file_url'];

							const res = await this.download_File(this.replaceBaseUrl(file_url, this.baseUrl), path.join(updateConfigDir, file_name));
							if (res == 0) {
								if (!this.versify(path.join(updateConfigDir, file_name), sign_md5)) {
									this.logger.error(path.join(updateConfigDir, file_name) + "文件校验失败");
									flag++;
								}
							} else {
								flag++;
							}
						}
					});

				} else {
					flag++;
				}
			} else {
				flag++;
			}
			let res = flag > 0 ? -1 : 0
			let configData = {
				res: res,
				g_index_Object: g_index_Object,
				osinfo: osinfo,
				osrelease: osrelease,
				supportList: supportList,
				ConfigMatch: ConfigMatch,
				base_url: g_index_Object['base-url'],
				depConfigInfo: osinfo !== "undefined" ? g_index_Object['config-file'][osinfo][0] : {}
			}
			return configData;
		} catch (error) {
			this.logger.error("网络数据校验失败" + error);
			let configData = {
				res: -1,
				g_index_Object: {},
				osinfo: "",
				ConfigMatch: -1,
				base_url: "",
				depConfigInfo: {},
				osrelease: "",
				supportList: []
			}
			return configData;
		}

	}

	private async loadAndInvokeFunction(modulePath: string, functionName: string, ...args: any[]): Promise<any> {
		try {
			const module = await import(modulePath);
			if (typeof module[functionName] === 'function') {
				const result = await module[functionName](...args);
				return result;
			} else {
				throw new Error(`Function '${functionName}' not found in module '${modulePath}'.`);
			}
		} catch (error) {
			if (error.name === 'AbortError') {
				this.logger.info("Execution aborted");
			} else {
				throw new Error(`Failed to load module '${modulePath}': ${error}`);
			}

		}
	}
	private async loadAndInvokeCancelFunction(modulePath: string, functionName: string, ...args: any[]) {
		return new Promise((resolve, reject) => {
			try {
				import(modulePath).then(async module => {
					if (typeof module[functionName] === 'function') {
						module[functionName](...args).then((res: []) => {
							resolve(1);
						}).catch((err: any) => {
							reject(err);
						})
					}
				})
			} catch (error) {
				if (error.name === 'AbortError') {
					this.logger.info("Execution aborted");
					reject(-1);
				} else {
					reject(-1);
					throw new Error(`Failed to load module '${modulePath}': ${error}`);
				}

			}
		})

	}
	readOSInfo() {
		this.println('readosinf');
		const kyinfoPath = '/etc/.kyinfo';
		const osReleasePath = '/etc/os-release';
		let osFile: string = '';
		let data = '';
		if (fs.existsSync(kyinfoPath)) {
			try {
				osFile = kyinfoPath;
				data = fs.readFileSync(kyinfoPath, 'utf8');
				data = data.replace(/\n/g, '<br>');
			} catch (err) {
			}
		} else if (fs.existsSync(osReleasePath)) {
			try {
				osFile = osReleasePath;
				data = fs.readFileSync(osReleasePath, 'utf8');
				data = data.replace(/\n/g, '<br>');
			} catch (err) { }
		}
		return { osFile, data }
	}
}

// function isStrictWindowState(obj: unknown): obj is IStrictWindowState {
// 	if (typeof obj !== 'object' || obj === null) {
// 		return false;
// 	}
// 	return (
// 		'x' in obj &&
// 		'y' in obj &&
// 		'width' in obj &&
// 		'height' in obj
// 	);
// }

// function getColor(theme: IColorTheme, key: string): string | undefined {
// 	const color = theme.getColor(key);
// 	return color ? color.toString() : undefined;
// }


export class DependInfo extends Disposable {

	private getDepends(pkgname: string[]) {
		let commands = "apt-cache depends --no-pre-depends --no-suggests --no-recommends --no-conflicts --no-breaks --no-enhances --no-replaces --recurse ";
		pkgname.forEach(item => {
			if (item) {
				commands += item + " ";
			}
		});

		return new Promise<string[]>((resolve, reject) => {
			const { exec } = require('child_process');
			exec(commands, (error: any, stdout: string, stderr: any) => {
				if (error) {
					reject(error);
				} else {
					let stdoutStr = stdout.toString();
					const lines = stdoutStr.split('\n');
					let dependsArry: string[] = [];
					let regstr: RegExp = /^[a-zA-Z]/;
					lines.forEach((line) => {
						if (regstr.test(line)) {
							if (line.trim() != "c-compiler" && line.trim() != "libc-dev")
								dependsArry.push(line.trim());
						}
					});//end lines

					resolve(dependsArry);
				}
			});
		});
	}

	public getRequiredAllDepends(pkList: string[]) {
		let baseDepends: string[] = [];
		return this.getBaseDepends().then((arg1) => {
			baseDepends = arg1;
			return this.getDepends(pkList);
		}).then((depends) => {
			return new Promise<string[]>((resolve, reject) => {
				let result: string[] = [];
				depends.forEach((item) => {
					if (baseDepends.indexOf(item) == -1) {
						result.push(item);
					}
				})
				resolve(result);
			});
		}).catch((error) => {
		})
	}

	private async getBaseDepends() {
		let basePkgList: string[] = ["systemd", "init", "udev", "bash", "coreutils", "base-files",
			"libc6", "kmod", "initramfs-tools"];
		return this.getDepends(basePkgList);
	}

}

// interface PkgDownInfo {
// 	name: string,
// 	version: string,
// 	epoch: string,
// 	state: string //downloaded,downloadFailed
// }
